前言
昨天我們幫「賽博紓壓診所」加上了日夜切換功能,版面瞬間有了科技感。但是當使用者點擊「進入紓壓診所」準備做測驗時,如果畫面只是瞬間切換過去,會顯得有點生硬。
既然我們的專題主打的是「紓壓」,那在進入正式的心理測驗前,總得先幫大家把緊繃的心情緩和下來。因此,我決定在中間穿插一個「深呼吸引導過場畫面(#breathe-screen)」。
很多漂亮的過場動畫都會依賴大型前端動畫套件(像是 GSAP 或 Framer Motion),但我這次堅持「零套件、純手刻」的原則。今天要來分享我是怎麼用純 CSS 的 @keyframes 刻出一個有韻律感、會自己放大縮小的呼吸燈圓圈!
核心觀念:用 @keyframes 打造呼吸節奏
CSS 動畫的核心就是 @keyframes(關鍵影格)。我們可以設定一個動畫名稱(例如 breatheAnimation),然後定義它在 0%、50%、100% 的不同時間點要產生什麼變化。
為了讓這個呼吸燈看起來夠柔和,我讓圓圈在 50%(也就是吸氣到最大、最放鬆的時候)放大 1.3 倍,同時把背景藍色調得更亮一點;然後在 0% 和 100% 時縮回原本大小。最後加上 infinite 讓它無限循環,並且設定 ease-in-out 讓縮放過程有緩入緩出的滑順感,才不會看起來像機械在抽動。
動手寫 Code(上):呼吸燈的 CSS 樣式與動畫定義
首先,我們在樣式表裡加入圓圈的基礎樣式,並綁定 @keyframes 動畫:
[data-theme="dark"] {
--bg-color: #121212;
--card-bg: #1e1e1e;
--primary-color: #64b5f6;
--text-main: #e0e0e0;
--text-muted: #9e9e9e;
}
body {
font-family: 'Segoe UI', Microsoft JhengHei, sans-serif;
background: var(--bg-color);
color: var(--text-main);
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
transition: background 0.3s, color 0.3s;
}
.container {
width: 100%;
max-width: 600px;
padding: 20px;
}
.card {
background-color: var(--card-bg);
border-radius: var(--border-radius);
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.15);
padding: 30px;
text-align: center;
transition: background-color 0.3s;
}
/* 呼吸燈圓圈設計 */
.breathe-circle {
width: 120px;
height: 120px;
background-color: #90caf9;
border-radius: 50%;
margin: 30px auto;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
/* 綁定動畫:總時長 4 秒、無限循環、緩入緩出 */
animation: breatheAnimation 4s infinite ease-in-out;
}
/* 定義呼吸燈的放大縮小與顏色漸變 */
@keyframes breatheAnimation {
0% { transform: scale(1); background-color: #90caf9; }
50% { transform: scale(1.3); background-color: #42a5f5; }
100% { transform: scale(1.0); background-color: #90caf9; }
}
.btn {
background-color: var(--primary-color);
color: white;
border: none;
border-radius: 50px;
padding: 12px 30px;
font-size: 1rem;
cursor: pointer;
width: 100%;
margin-top: 10px;
}
.hidden { display: none; }
</style>
動手寫 Code(下):過場畫面結構與互動邏輯
接著,我們把 #breathe-screen 的結構寫好。當使用者從首頁點擊進入後,除了切換畫面之外,我還用 JavaScript 寫了一個簡單的計時器,讓中間的文字隨著秒數在「吸氣...」和「呼氣...」之間切換,營造出更真實的引導感:
<div class="container">
<!-- 1. 首頁區塊 -->
<div id="welcome-screen" class="card">
<h1>🧠 賽博紓壓診所與解碼器</h1>
<p>結合廟宇抽籤、六角形能力雷達圖與惡搞處方籤的頂級心靈小工具。</p>
<button class="btn" onclick="goToBreathe()">進入紓壓診所</button>
</div>
<!-- 2. 深呼吸過場區塊(預設隱藏) -->
<div id="breathe-screen" class="card hidden">
<h2>🧘 調整呼吸,放鬆心情</h2>
<p>請跟隨圓縮放的節奏,深吸氣... 吐氣...</p>
<!-- 呼吸燈圓圈本體 -->
<div class="breathe-circle" id="breathe-text">吸氣...</div>
<button class="btn" onclick="startQuiz()">準備好了,開始解碼</button>
</div>
<!-- 3. 測驗區塊(預設隱藏) -->
<div id="quiz-screen" class="card hidden">
<h2>心理測驗題目載入中...</h2>
</div>
</div>
<script>
// 切換到呼吸過場畫面,並用簡單的計時器切換文字提示
function goToBreathe() {
document.getElementById('welcome-screen').classList.add('hidden');
document.getElementById('breathe-screen').classList.remove('hidden');
let step = 0;
const breatheText = document.getElementById('breathe-text');
// 每 2 秒切換一次吸氣/呼氣文字,配合 4 秒的動畫週期
const interval = setInterval(() => {
step++;
if (step === 1) breatheText.innerText = "呼氣...";
if (step === 2) breatheText.innerText = "吸氣...";
if (step >= 4) clearInterval(interval);
}, 2000);
}
function startQuiz() {
document.getElementById('breathe-screen').classList.add('hidden');
document.getElementById('quiz-screen').classList.remove('hidden');
}
</script>
開發小想法與設計巧思
在規劃這個過場畫面的時候,我花了很多時間思考:怎樣才能真正達到「減壓」的效果?
市面上很多測驗一進去就是密密麻麻的題目,對於已經很焦慮的人來說,有機率會造成額外的壓迫感。因此,我試著在前端互動中加入一點「儀式感」——透過純 CSS 的圓圈縮放與溫和的漸層色,讓使用者在點進測驗前,能下意識跟著畫面慢下呼吸。雖然只是很小的前端特效,但這是我在思考專題創新時,希望能為使用者多做的一點貼心小細節。
今日結語與明日預告
今天我們完全不靠任何外部套件,只用純 CSS 的 @keyframes 就刻出了流暢的呼吸燈動畫,順便用 JavaScript 串起了過場文字的切換。
明天 Day 05:SPA 單頁式應用架構:用原生 JS 控制畫面狀態與流暢切換,我們要把前面幾天零散的畫面串聯起來,建立一套乾淨、好擴充的單頁應用切換機制。我們明天見!